/**
 *
 */
package com.honeybees.framework.mybatis.sqlsource;

import java.util.List;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.session.Configuration;

import com.honeybees.framework.mybatis.interceptor.PaginationInterceptor;
import com.honeybees.framework.pagination.dialect.Dialect;
import com.honeybees.framework.spring.mvc.model.ModelSupport;

/**
 * <dl>
 * <dt><b> 支持分页功能的SqlSource </b></dt>
 * <p>
 * <dd>功能描述</dd>
 * </dl>
 * <p>
 * Copyright (C) All rights reserved.
 * </p>
 *
 * @author 李远明
 * @since 2016年7月20日 下午6:03:29
 */
public abstract class AbstractPageSqlSource implements SqlSource {

    /**
     * MyBatis 的配置信息
     *
     * @version 2016-07-27 11:39:55 将 MyBatis 配置信息从 AbstractPageSqlSource 的子类移到父类
     */
    protected Configuration configuration;
    /**
     * @version 2016-07-27 11:42:25 数据库方言
     */
    protected Dialect dialect = null;

    /**
     * 分页参数
     */
    protected int offset;
    /**
     * 分页参数
     */
    protected int limit;

    /**
     * <dl>
     * <dt><b> 获取用于普通查询的 BoundSql </b></dt>
     * <p>
     * <dd>上周六在床上躺着的时候，突然想起，如果先执行分页查询，
     * {@link PaginationInterceptor#processMappedStatement(org.apache.ibatis.mapping.MappedStatement)}方法中已经将
     * SqlSource 替换为分页的 SqlSource，那么再执行普通的查询，会有错误。应该在 {@link #getBoundSql(Object)}方法中，返回普通的
     * BoundSql，用于普通查询。</dd>
     * </dl>
     *
     * @param parameterObject 查询参数
     * @return 普通查询的SQL语句
     * @author 李远明
     * @version 2016年7月25日 上午10:02:59
     */
    protected abstract BoundSql getDefaultBoundSql(Object parameterObject);

    /**
     * <dl>
     * <dt><b> 获取Count查询的BoundSql </b></dt>
     * <p>
     * <dd>功能描述</dd>
     * </dl>
     *
     * @param parameterObject 查询参数
     * @return 查询数据总条数的SQL语句
     * @author 李远明
     * @version 2016年7月20日 下午8:23:04
     */
    protected abstract BoundSql getCountBoundSql(Object parameterObject);

    /**
     * <dl>
     * <dt><b> 获取分页查询的BoundSql </b></dt>
     * <p>
     * <dd>功能描述</dd>
     * </dl>
     *
     * @param parameterObject 查询参数
     * @return 分页查询SQL语句
     * @author 李远明
     * @version 2016年7月20日 下午8:23:33
     */
    protected abstract BoundSql getPageBoundSql(Object parameterObject);

    /**
     * 获取BoundSql
     *
     * @param parameterObject 查询对象
     * @author 李远明
     * @version 2016年7月20日 下午6:03:29 新建
     * @version 2016年7月25日 上午10:24:30 如果当前方法中，取得的三个分页参数都为0，则表示先执行了分页查询，再执行普通查询；执行普通查询的时候，要返回普通的
     * BoundSql。
     * @see com.honeybees.framework.mybatis.MyBatisDaoSupport#selectPage(String, Object)
     */
    @Override
    public BoundSql getBoundSql(Object parameterObject) {

        int totalCount;
        if (parameterObject instanceof ModelSupport) {
            ModelSupport model = (ModelSupport) parameterObject;
            totalCount = model.getTotalCount();
            offset = model.getOffset();
            limit = model.getLimit();
        } else {
            String msg = "分页查询时，所有查询对象必须继承模型基类：" + ModelSupport.class.getName();
            throw new IllegalArgumentException(msg);
        }

        // 实例化数据库方言，后续的 getCountBoundSql、getPageBoundSql 两个方法中使用
        if (dialect == null) {
            if (configuration != null) {
                String databaseId = configuration.getDatabaseId();
                Dialect dbDialect = Dialect.Type.forType(databaseId);
                if (dbDialect == null) {
                    String msg = "获取数据库方言失败，请检查MyBatis配置：请配置 SqlSessionFactoryBean 参数“databaseIdProvider”的值为：【org.apache.ibatis.mapping.VendorDatabaseIdProvider】";
                    throw new IllegalStateException(msg);
                }
                this.dialect = dbDialect;
            }
        }

        BoundSql boundSql;
        if (totalCount == 0 && offset == 0 && limit == 0) {
            boundSql = getDefaultBoundSql(parameterObject);
        } else if (totalCount == 0) {
            boundSql = getCountBoundSql(parameterObject);
        } else {
            boundSql = getPageBoundSql(parameterObject);
        }
        return boundSql;
    }

    /**
     * <dl>
     * <dt><b> 获取分页参数映射 </b></dt>
     * <p>
     * <dd>功能描述</dd>
     * </dl>
     *
     * @param configuration MyBatis 配置信息
     * @param boundSql      SQL语句
     * @return 参数映射
     * @author 李远明
     * @version 2016年7月21日 下午5:40:05
     */
    protected List<ParameterMapping> getPageParameterMapping(Configuration configuration, BoundSql boundSql) {
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        return parameterMappings;
    }

}
